#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctype.h>
#include<unistd.h>
#include<cstring>
#include<sys/types.h>
#include<sys/wait.h>
#define COMMANDSIZE 1024
#define FORMAT "[%s@%s %s]#"


//shell内部维护的全局变量
#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc=0;

//for test
char g_cwd[1024];
char cwdenv[1024];


//shell内部维护的环境变量表
char *g_env[100];
int envs;

//最近一次进程的退出码
int lastcode=0;

//重定向支持的宏和变量

#define NONE_RDIR 0
#define INPUT_RDIR 1
#define OUTPUT_RDIR 2
#define APPEND_RDIR 3

//默认没有重定向
int redir=NONE_RDIR;

std::string filename;



const char *GetHostName()
{
    const char* hostname=getenv("HOSTNAME");
    return hostname == NULL ?  "None" : hostname;
}

const char *GetUser()
{
    const char* user=getenv("USER");
    return user == NULL ? "None" : user;
}

const char  *GetPwd()
{
    const char* pwd=getcwd(g_cwd,sizeof(g_cwd));
    if(pwd != NULL)
    {
        snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",pwd);
        putenv(cwdenv);
    }
    return pwd == NULL ? "None" : pwd;
}

const char *GetHome()
{
    const char *home=getenv("HOME");
    return home == NULL ? "" : home;
}

//切割路径
#define SLASH "/"
std::string DirName(const char *pwd)
{
    std::string dir=pwd;
    if(dir == SLASH) return SLASH;
    auto pos = dir.rfind(SLASH);
    if(pos == std::string::npos) return "BUG?";
    return dir.substr(pos+1); 
}


void MakeCmdlinePrompt(char cmd_prompt[],int size)
{
    snprintf(cmd_prompt,size,FORMAT,GetUser(),GetHostName(),DirName(GetPwd()).c_str());
}

void PrintCmdline()
{
    char cmd_prompt[COMMANDSIZE];
    MakeCmdlinePrompt(cmd_prompt,sizeof(cmd_prompt));
    printf("%s",cmd_prompt);
    fflush(stdout);
}


bool GetCmdline(char cmd[],int size)
{
        char *c=fgets(cmd,size,stdin);
        if(c == NULL) return false;
        cmd[strlen(cmd)-1]=0;
        if(strlen(cmd) == 0) return false;
        return true;
}


//命令行分析
//定义一个分隔符

#define SAP " "
bool CommandPrase(char *cmd)
{
    g_argc=0;
    g_argv[g_argc++]=strtok(cmd,SAP);
    while((bool)(g_argv[g_argc++]=strtok(nullptr,SAP)));
    g_argc--;
    if(g_argc == 0)
        return false;
    return true;
}


void DebugArgv()
{
    for(int i=0;g_argv[i];++i)
    {
        printf("g_argv[%d]->%s\n",i,g_argv[i]);
    }
    printf("g_argc->%d\n",g_argc);
}


bool Cd()
{
    if(g_argc == 1)
     {
         std::string home = GetHome();
         if(home.empty())
             return true;
         chdir(home.c_str());
         return true;
     }
     else 
     {
         std::string where= g_argv[1];
         chdir(where.c_str());
         return true;
     }
     return false;
}

void Echo()
{
    std::string what=g_argv[1];
    if(what == "$?")
    {
        std::cout<<lastcode<<std::endl;
        lastcode=0;
    }
    if(what[0] == '$')
    {
        std::string env_name=what.substr(1);
        const char *env_value=getenv(env_name.c_str());
        if(env_value)
            std::cout<<env_value<<std::endl;
    }
    else 
    {
        std::cout<<what<<std::endl;
    }
}

//导入环境变量
extern char **environ;
void InitEnv()
{
    for(int i=0;environ[i];i++)
    {
        g_env[i]=(char*)malloc(strlen(environ[i])+1);
        if(g_env[i] == NULL)
        {
            perror("malloc failed!\n");
            exit(1);
        }
        strcpy(g_env[i],environ[i]);
        envs++;
    }
    g_env[envs++]=(char*)"AAA=11223344";
    g_env[envs]=NULL;
    for(int i=0;g_env[i];++i)
    {
        putenv(g_env[i]);
    }
}




//处理空格得到文件名的首字母
void  DeleSpace(char cmd[],int& end)
{
    while(isspace(cmd[end]))
    {
        end++;
    }

}
void CheckRedir(char cmd[])
{
    redir=NONE_RDIR;
    filename.clear();
    int end=strlen(cmd)-1;
    //"ls -a -l >> log.txt"
    while(end > 0)
    {
        //"ls -a -l < filename.txt"
        if(cmd[end] == '<')
        {
            cmd[end++]=0;
            DeleSpace(cmd,end);
            redir=INPUT_RDIR; 
            filename=cmd+end;
            break;
        }
        else if(cmd[end] == '>')
        {
            if(end > 0 && cmd[end - 1] == '>')
            {
                cmd[end-1]=0;
                redir=APPEND_RDIR;
                cmd[end++]=0;
                DeleSpace(cmd,end);
                filename=cmd+end;
                break;
            }
            else 
            {
                redir=OUTPUT_RDIR;
                cmd[end++]=0;
                DeleSpace(cmd,end);
                filename=cmd+end;
                break;
            }
        }
        else 
        {
            end--;
        }
    }
}

bool CheckandProcBuildin()
{
    std::string cmd=g_argv[0];
    if(cmd == "cd")
    {
        Cd();
        return true;
    }
    else if(cmd == "echo")
    {
        Echo();
        return true;
    }
    return false; 
}

//创建子进程执行命令
int Execute()
{
    //创建子进程执行命令
     pid_t id=fork();
     if(id ==0)
     {
         //子进程
         execvp(g_argv[0],g_argv);
         exit(1);
     }
     int status=0;
     pid_t rid=waitpid(id,&status,0);
     if(rid > 0)
     {
         if(WIFEXITED(status))
         {
            lastcode = WEXITSTATUS(status);
         }
         else 
         {
             lastcode=100;
             return 1;
         }
     }
     return 0;
}
int main()
{
    InitEnv();
    while(true)
    {
        //打印命令行提示符
        PrintCmdline();
        //获取用户输入的命令
        char cmdline[COMMANDSIZE];
        if(!GetCmdline(cmdline,sizeof(cmdline)))
            continue;
        //分析用户输入的命令
        if(!CommandPrase(cmdline))
            continue;
         //DebugArgv();
       
        //判断重定向并处理
        CheckRedir(cmdline);
        printf("%d,%s\n",redir,filename.c_str());       
        
        //判断并且处理内建命令
        //if(CheckandProcBuildin())
        //    continue;
       
        
        //创建子进程执行命令
       // Execute();
    }
    return 0;
}
